//--------------------------------------------------------------------------------
// This file is a portion of the D2D1Renderer.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Mirco Timmermann
//
//--------------------------------------------------------------------------------
#include "EventDispatcher.h"

/*
* ...->addEventListener("ENTER_FRAME", boost::bind(&SpriteSheetComponent::ON_ENTER_FRAME_timeline, this, _1)); //method pointer (Boost)
* ...->addEventListener("ENTER_FRAME", std::bind(&SpriteSheetComponent::ON_ENTER_FRAME_timeline, this, std::placeholders::_1)); //method pointer (C++11)
*
* ...->addEventListener("ENTER_FRAME", ON_ENTER_FRAME_timeline);  //function pointer
*
* void Console::ON_ENTER_FRAME_timeline(const Event &event) { }
*/
void EventDispatcher::addEventListener(const std::string &type, FunctionPtr listener, bool useCapture, int priority, bool useWeakReference) {
	eventHandlerList[type][priority].push_back(listener);
}

/*
* TODO: not working fuction. Have to be look for a workaround to remove functions.
*/
void EventDispatcher::removeEventListener(const std::string &type, FunctionPtr listener, bool useCapture) {
	//break if no eventListener registered.
	if(!hasEventListener(type)) return;
	
	//Reference to keep the code clean
	std::map<int, std::list<FunctionPtr>> &allFunctions = eventHandlerList[type];

	//Since we don't know the function's priority, we'll search for it
	for(std::map<int, std::list<FunctionPtr>>::iterator i = allFunctions.begin(); i != allFunctions.end(); ++i) {
		std::list<FunctionPtr> list = i->second;

		//Remove object from the map if list gone empty to eliminate false positives.
		if(i->second.empty()) allFunctions.erase(i);
	}
	//Remove map to eliminate false positives
	if(allFunctions.empty()) eventHandlerList.erase(type);
}

/*
* checks if an eventlistener exists.
*/
bool EventDispatcher::hasEventListener(const std::string &type) {
	return (eventHandlerList.find(type) != eventHandlerList.end());
}

/*
* throws events out.
*/
void EventDispatcher::dispatchEvent(const Event &event) {
	// Leave if no event registered
	if(!hasEventListener(event.type)) return;
 
	// A reference to keep code clean
	std::map<int, std::list<FunctionPtr>> &allFunctions = eventHandlerList[event.type];
 
	// Iterate through all functions in the event, from high proproty to low
	for(std::map<int, std::list<FunctionPtr > >::reverse_iterator i=allFunctions.rbegin(); i!=allFunctions.rend(); ++i) {
		std::list<FunctionPtr > &funcList = i->second;
		// Execute callbacks
		for(std::list<FunctionPtr >::iterator f = funcList.begin(); f!=funcList.end(); ++f) {
			(*f)(event);
		}
	}
}